using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data;
using System.Diagnostics;
using System.Configuration;

namespace NUnitHelper.Managers
{
    public class CompilerManager
    {

        static CompilerManager()
        {
            RestartOnRecompile = ConfigurationManager.AppSettings["always_restart_nunit"].Equals("true", StringComparison.OrdinalIgnoreCase);
        }

        private static Process _NUnitProcess = null;
        private static Process NUnitProcess
        {
            get
            {
                return _NUnitProcess;
            }
            set
            {
                _NUnitProcess = value;
            }
        }

        private static bool _restartOnRecompile;
        public static bool RestartOnRecompile
        {
            get
            {
                return _restartOnRecompile;
            }
            set
            {
                _restartOnRecompile = value;
            }
        }


        public static string GetTempLocation()
        {
            return GetTempLocation("");
        }

        public static string GetTempLocation(string s)
        {
            if (s.Length > 0)
            {
                if (!s.StartsWith(@"\"))
                {
                    s = string.Format(@"\{0}", s);
                }
            }
            
            return string.Format(@"{0}nunit_helper\website{1}", Path.GetTempPath(), s);
        }

        public static string ReCompile(string filepath)
        {

            if (RestartOnRecompile)
            {
                CloseNUnit();
            }

            string tempdir = GetTempLocation();
            string sourceDir = filepath;

            string compiler = ConfigurationManager.AppSettings["aspnet_compiler"];
            string commandLine = String.Format(@"-f -p ""{0}"" -v / ""{1}""", sourceDir, tempdir);
            if (Directory.Exists(tempdir))
            {
                Directory.Delete(tempdir, true);
            }
            Directory.CreateDirectory(tempdir);

            ProcessStartInfo p = new ProcessStartInfo(compiler, commandLine);
            p.UseShellExecute = false;
            p.RedirectStandardOutput = true;
            p.RedirectStandardError = true;
            p.CreateNoWindow = true;
            p.WindowStyle = ProcessWindowStyle.Hidden;

            Process myProcess = Process.Start(p);

            StreamReader outputReader = myProcess.StandardOutput;
            

            myProcess.WaitForExit();

            string commandLineResult = outputReader.ReadToEnd();
            outputReader.Close();

            if (commandLineResult.Contains("error"))
            {
                throw new Exception(commandLineResult);
            }

            StringBuilder result = new StringBuilder();
            result.AppendLine("Messages:");
            result.AppendLine(commandLineResult);
            result.AppendLine("Done");


            FixFilesForNUnit();

            if (RestartOnRecompile)
            {
                ReStartNUnit();
            }

            return result.ToString() ;
        }

        public static void CloseNUnit()
        {
            if (NUnitProcess != null)
            {
                if (!NUnitProcess.HasExited)
                {
                    NUnitProcess.CloseMainWindow();
                    NUnitProcess.WaitForExit(10 * 1000); // wait for 10 seconds
                    if (!NUnitProcess.HasExited)
                    {
                        NUnitProcess.Kill(); // thirst for blood!
                    }
                }
            }
        }

        private static void ReStartNUnit()
        {
            string NUnitExe = ConfigurationManager.AppSettings["nunit_executable"];
            string commandLine = string.Format("\"{0}\"", GetTempLocation(@"\bin\App_Code.dll"));

            CloseNUnit();
            NUnitProcess = Process.Start(NUnitExe, commandLine);
        }

        private static void FixFilesForNUnit()
        {
            // need to move databases in App_Code directory to root directory, 
            // otherwise code will throw a "database already attached" error.
            foreach (string filename in Directory.GetFiles(GetTempLocation(@"\App_Data")))
            {
                File.Move(filename, GetTempLocation(Path.GetFileName(filename)));
            }

            // need to edit web.config's connection strings, then save its contents
            // to bin directory
            string webConfigPath = GetTempLocation("web.config");
            string appConfigPath = GetTempLocation(@"bin\App_Code.dll.config");
            
            string newConfig = File.ReadAllText(webConfigPath);
            newConfig = newConfig.Replace("|DataDirectory|", GetTempLocation());
            File.WriteAllText(appConfigPath, newConfig);
        }
    }
}
